package com.nlp.solve.issue_a;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nlp.model.Article;
import com.nlp.solve.ExportExcel;
import com.nlp.solve.Main;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

//我国总体与分学科国际科研合作
@Component
public class Issue_A implements ExportExcel {
    private Logger logger = LoggerFactory.getLogger(Issue_A.class);


    @Value("${input.file.dir}")
    private String inputDir;

    @Value("${output.file.dir}")
    private String outputDir;
//
//    public void main(String[] args) throws NoSuchMethodException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
//
////        solve(inputDir,outputDir);
//        Map<String, Map<String, Map<String, Integer>>> s = statistic(outputDir);
//        try (DataOutputStream dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputDir + "statistic.json")))) {
//            JSON.writeJSONString(dataOutputStream, StandardCharsets.UTF_8, s);
//        }
//    }

    public void issue_a(String resultFile, String outputDir) throws NoSuchMethodException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
        //solve(inputDir,outputDir);
        Map<String, Map<String, Map<String, Integer>>> s = statistic(outputDir);
        try (DataOutputStream dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(resultFile)))) {
            JSON.writeJSONString(dataOutputStream, StandardCharsets.UTF_8, s);
        }
    }

    public static void main(String[] args) throws IOException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        Issue_A issue_a = new Issue_A();
//        File dir = new File("F:\\IdeaProjects\\NLP2.0\\src\\test\\tmp\\issue_a\\");
//        File[] files = dir.listFiles();
//        HSSFWorkbook workbook = new HSSFWorkbook();
//        for (File file : files) {
//            if (!file.isDirectory()) {
        //依赖于result.json
//        excel2("F:\\IdeaProjects\\NLP2.0\\src\\test\\tmp\\result.json");
//                Sheet sheet = workbook.createSheet(file.getName().split("\\.")[0]);
//                issue_a.excel(workbook, file);
//                excel(sheet,file);
//            }
//        }
//        String outP = "issue_a_all" + ".xls";
//        try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(outP))) {
//            workbook.write(dataOutputStream);
//        }
//        Issue_A issue_a = new Issue_A();
        issue_a.solve(issue_a.inputDir, "F:\\IdeaProjects\\NLP2.0\\src\\test\\tmp\\");
    }

//    private static void excel2(String abs) throws IOException {
//        //国家 :{年份：｛学科：次数｝}
//        HSSFWorkbook workbook = new HSSFWorkbook();
//        HSSFSheet sheet = workbook.createSheet();
//        Map<String, Map<String, Map<String, Integer>>> map = JSONObject.parseObject(Main.read(abs), Map.class);
//        TreeSet<String> years = new TreeSet<>();
//        for (Map.Entry<String, Map<String, Map<String, Integer>>> entry : map.entrySet()) {
//            for (Map.Entry<String, Map<String, Integer>> e : entry.getValue().entrySet()) {
//                years.add(e.getKey());
//            }
//        }
//        int index = 0;
//        try (DataOutputStream dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("./issue_a_all_2.xlsx")))) {
//            workbook.write(dataOutputStream);
//        }
//
//        System.out.println(years);
//    }

    private Set<String> xAxis = new TreeSet<>();

    public void excel(Sheet sheet, File file) throws IOException {
        logger.info("file path: {}", file.getAbsolutePath());
        String abs = file.getAbsolutePath();
//        res = new TreeMap<>();
        Map<String, JSONArray> map = JSONObject.parseObject(Main.read(abs), Map.class);
        Map<String, Map<String, Integer>> res = new HashMap<>();
        LinkedHashSet<String> cates = new LinkedHashSet<>();
        //Set<String> xAxis = new TreeSet<>();
        for (Map.Entry<String, JSONArray> entry : map.entrySet()) {
            String key = entry.getKey();
            xAxis.add(key);
            JSONArray arr = entry.getValue();
            Map<String, Integer> m_ = res.computeIfAbsent(key, l -> new LinkedHashMap<>());
            for (int i = 0; i < arr.size(); i++) {
                Map<String, Integer> t = arr.getObject(i, Map.class);
                Set<String> strings = t.keySet();
                for (String k : strings) {
                    m_.put(k, m_.getOrDefault(k, 0) + t.get(k));
                    cates.add(k);
                }
//                obj.get
//                Map<String,Integer> o = entry.getValue().get(i);
                // JSONObject e = entry.getValue().get(i);
            }
        }
        xAxis = xAxis.stream().sorted((String::compareTo)).collect(Collectors.toCollection(LinkedHashSet::new));
        cates = cates.stream().sorted((o1, o2) -> {
            Integer v1 = res.get("2020").get(o1) == null ? 0 : res.get("2020").get(o1);
            Integer v2 = res.get("2020").get(o2) == null ? 0 : res.get("2020").get(o2);
            return v2 - v1;
        }).collect(Collectors.toCollection(LinkedHashSet::new));
        int i = 0;
        int j = 0;
        Row r = sheet.createRow(0);
        for (String xAxi : xAxis) {
            r.createCell(++j).setCellValue(xAxi);
        }
        Map<String, Integer> yearCount = new TreeMap<>();
        for (String cate : cates) {
            Row row = sheet.createRow(++i);
            j = 0;
            row.createCell(j).setCellValue(cate);
            int count = 0;
            for (String year : xAxis) {
                int i1 = 0;
                if (res.get(year) != null) {
                    i1 = res.get(year).get(cate) == null ? 0 : res.get(year).get(cate);
                }
                yearCount.put(year, yearCount.getOrDefault(year, 0) + i1);
                count += i1;
                row.createCell(++j).setCellValue(i1);
            }
            row.createCell(++j).setCellValue(count);
        }
        Row row = sheet.createRow(++i);
        j = 0;
        for (Map.Entry<String, Integer> entry : yearCount.entrySet()) {
            //  String year = entry.getKey();
            Integer value = entry.getValue();
            row.createCell(++j).setCellValue(value);
        }
        //System.out.println(yearCount);
    }

    //按照年份的
    public void excel(Workbook workbook, File file) throws IOException {
        Sheet sheet = workbook.createSheet(file.getName().split("\\.")[0]);
        excel(sheet, file);
    }

    private Map<String, Map<String, Map<String, Integer>>> statistic(String outputDir) throws IOException {
        Map<String, Map<String, Map<String, Integer>>> map = new HashMap<>();
        statistic_(new File(outputDir), map);
        return map;
    }

    private void statistic_(File file, Map<String, Map<String, Map<String, Integer>>> map) throws IOException {
        File[] files = file.listFiles();
        for (File f : files) {
            if (f.isDirectory()) {
                statistic_(f, map);
            } else {
                resolveStatistic(f, map);
            }
        }
        System.out.println(map.size());
    }

    private void resolveStatistic(File f, Map<String, Map<String, Map<String, Integer>>> map) throws IOException {
        if (!f.getName().contains("statistic")) {
            return;
        }
        String json = Main.read(f.getAbsolutePath());
        Map m = JSONObject.parseObject(json, Map.class);
        map.put(f.getName().split("_")[0].toLowerCase(Locale.ROOT), m);
    }

    public void solve(String inputDir, String outputDir) throws NoSuchMethodException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
        File file = new File(inputDir);
        File[] files = file.listFiles();
        for (File f : files) {
            System.out.println(f.getAbsolutePath());
            if (f.isDirectory()) {
                wrestleAll(f.getAbsolutePath(), outputDir + f.getName() + "\\");
            }
        }
    }

    //处理某一国家的全部
    private void wrestleAll(String inputDir, String outputDir) throws NoSuchMethodException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
        Map<String, Map<String, Integer>> countryYearMap = new HashMap<>();
        File file = new File(inputDir);
        String fn = file.getName() + "_statistic.json";
        File[] files = file.listFiles();
        logger.info("-------------[{}]-------------", file.getName());
        for (File f : files) {
            if (f.isDirectory()) {
                wrestleAll(f.getAbsolutePath(), outputDir + f.getName() + "\\");
            } else {
//                System.out.println(f.getAbsolutePath());
                String fileName = f.getName();
                if (fileName.endsWith(".txt")) {
                    String outP = outputDir + fileName + ".json";
                    //生成一个对应的json文件
                    // Main.resolve(f.getAbsolutePath(), outP);
                    //汇总statistic数据
                    wrestle(outP, countryYearMap);
                }
            }
        }
        int count = 0;

        for (Map.Entry<String, Map<String, Integer>> entry : countryYearMap.entrySet()) {
            for (Map.Entry<String, Integer> e : entry.getValue().entrySet()) {
                count += e.getValue();
            }
        }
        logger.info("generate {}", fn);
        try (DataOutputStream dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputDir + fn)))) {
            JSONObject.writeJSONString(dataOutputStream, StandardCharsets.UTF_8, countryYearMap);
        }
        Main.count = 0;
    }

    private void wrestle(String abs, Map<String, Map<String, Integer>> countryYearMap) throws IOException {
//        File file = new File(dir);
//        File[] files = file.listFiles();
//        for (int i = 0; i < files.length; i++) {
//            if (!files[i].isDirectory() && !files[i].getName().contains("statistic")) {
//                wrestle_(files[i].getAbsolutePath(), countryYearMap);
//            }
//        }
        wrestle_(abs, countryYearMap);
    }

    private void wrestle_(String abs, Map<String, Map<String, Integer>> countryYearMap) throws IOException {
        int count = 0;
        String json = Main.read(abs);
        List<Article> articles = JSONObject.parseArray(json, Article.class);
        logger.info("articles count: {}", articles.size());
        for (Article article : articles) {
            count++;
            String year = article.getPY();
            if (year == null || "null".equals(year) || "2021".equals(year)) {
                continue;
            }
            countryYearMap.computeIfAbsent(year, l -> new HashMap<>(50));
            Map<String, Integer> listMap = countryYearMap.get(year);
            String[] rds = article.getSC();
            if (rds != null && rds.length > 0) {
                for (String rd : rds) {
                    listMap.put(rd, listMap.getOrDefault(rd, 0) + 1);
                }
            }
        }
        System.out.println(count);
        logger.info("Finish resolving in : {}\n", abs);
    }

    //year => {学科:次数}
    private Map<String, Map<String, Integer>> transfer(String country, String abs, String outputDir) throws IOException {
        Main main = new Main();
        String json = Main.read(abs);
        Map<String, Map<String, Map<String, Integer>>> m = JSONObject.parseObject(json, Map.class);
        Map<String, Map<String, Integer>> yearMap = m.get(country);
        Map<String, Map<String, Integer>> map = new HashMap<>();
        for (Map.Entry<String, Map<String, Integer>> mapEntry : yearMap.entrySet()) {
            Map<String, Integer> m3 = mapEntry.getValue();
            //出现次数
            for (Map.Entry<String, Integer> entry1 : m3.entrySet()) {
                Map<String, Integer> m_ = map.computeIfAbsent(mapEntry.getKey(), l -> new HashMap<>());
//                    System.out.println(entry1.getKey()+":"+entry1.getValue());
                m_.put(entry1.getKey(), m_.getOrDefault(entry1.getKey(), 0) + entry1.getValue());
            }
        }
        Map<String, List<Map.Entry<String, Integer>>> res = new TreeMap<>();
        for (Map.Entry<String, Map<String, Integer>> entry : map.entrySet()) {
            List<Map.Entry<String, Integer>> list = res.computeIfAbsent(entry.getKey(), l -> new ArrayList<>(entry.getValue().entrySet()));
            main.quickSort(list, 0, list.size() - 1);
        }
        String out = outputDir + "issue_a_" + country + ".json";
        Main.write(res, out);
        return map;
    }

    public String transfer(String abs, String outputDir) throws IOException {
        Main main = new Main();
        String json = Main.read(abs);
        Map<String, Map<String, Map<String, Integer>>> m = JSONObject.parseObject(json, Map.class);
        Map<String, Map<String, Integer>> map = new HashMap<>();
        //year ->{学科：count}
        //国家
        for (Map.Entry<String, Map<String, Map<String, Integer>>> entry : m.entrySet()) {
            String key = entry.getKey();//国家
            //该国家的对应的map
            Map<String, Map<String, Integer>> m_country = transfer(key, abs, outputDir);
            //现在需要将该国家的map添加至总的
            for (Map.Entry<String, Map<String, Integer>> e : m_country.entrySet()) {
                Map<String, Integer> stringIntegerMap = e.getValue();
                for (Map.Entry<String, Integer> entry1 : stringIntegerMap.entrySet()) {
                    Map<String, Integer> map1 = map.computeIfAbsent(e.getKey(), l -> new HashMap<>());
                    map1.put(entry1.getKey(), map1.getOrDefault(entry1.getKey(), 0) + entry1.getValue());
                }
            }
        }
        Map<String, List<Map.Entry<String, Integer>>> res = new TreeMap<>();
        for (Map.Entry<String, Map<String, Integer>> entry : map.entrySet()) {
            List<Map.Entry<String, Integer>> list = res.computeIfAbsent(entry.getKey(), l -> new ArrayList<>(entry.getValue().entrySet()));
            main.quickSort(list, 0, list.size() - 1);
        }
        Main.write(res, outputDir + "issue_a_all.json");
        return outputDir + "issue_a_all.json";
    }
}
